/******************************************************************************
 * * alarm_main.c - implementation of alarm main functions
 *
 * *(C) Copyright 2019 Asr International Ltd.
 * * All Rights Reserved
 * ******************************************************************************/
#include "alarm_global.h"

/**********************
* GLOBAL VARIABLES
**********************/
const INT8 *g_Alarm_Ringing_Tone[ALARM_RING_TONE_COUNT] =
{
    "Standard",
    "Nokia Tune",
    "Brikabrak",
    "Trace",
    "Urgent",
    "Message 2"
};

Alarm_Mng_t g_Alarm_Mng;

/**
 * Alarm APP main entrance
 * param (in) void
 * return  void
 */
VOID Alarm_Main(VOID)
{
    Display_Alarm();
}

/**
 * Handle for stopping the alarm which is ringing
 * param (in) Delay: BOOL, TRUE if snooze
 * return  VOID
 */
VOID Alarm_Ring_Stop_Handle(BOOL Delay)
{
    If_Setting_Play_Tone_t *PlayToneReq = NULL;
    NV_UI_Alarm_Info_t     *AlarmInfo;
    UINT8                  i;
    BOOL                   AlarmChg    = FALSE;
    BOOL                   SetRtcAlarm = FALSE;

    // play tone stop
    PlayToneReq           = (If_Setting_Play_Tone_t *)Hal_Mem_Alloc(sizeof(If_Setting_Play_Tone_t));
    PlayToneReq->PlayCtrl = IF_SETTING_PLAY_TONS_STOP;
    PlayToneReq->ToneType = IF_SETTING_TONS_TYPE_ALARM;
    Setting_Play_Tone_Req(PlayToneReq);

    AlarmInfo = &g_Alarm_Mng.Alarm.AlarmInfo[g_Alarm_Mng.RingAlarmId];

    Nav_Back(ACT_ID_ALARM_RING);
    if (TRUE == Delay) // snooze
    {
        if (6 * 24 == AlarmInfo->RepeatCount)
        {
            AlarmInfo->RepeatCount = 1;
        }
        else
        {
            AlarmInfo->RepeatCount++;
        }
        AlarmChg    = TRUE;
        SetRtcAlarm = TRUE;

        Display_Alarm_Status(ACT_ID_ALARM_RING_DELAY);
    }
    else // stop
    {
        if (0 == (AlarmInfo->RepeatBitmap & 0x80)) // once ring
        {
            Hal_Mem_Set(AlarmInfo, 0, sizeof(NV_UI_Alarm_Info_t));
            AlarmChg = TRUE;
        }
        else if (0 != AlarmInfo->RepeatCount)
        {
            AlarmInfo->RepeatCount = 0;
            AlarmChg    = TRUE;
            SetRtcAlarm = TRUE;
        }

        Display_Alarm_Status(ACT_ID_ALARM_RING_OFF);
    }
    printf("%s: Delay %d, AlarmChg %d, SetRtcAlarm %d\n",
           __FUNCTION__, Delay, AlarmChg, SetRtcAlarm);

    if (TRUE == AlarmChg)
    {
        UI_NV_Write_Req(NV_SECTION_UI_ALARM,
                        0,
                        sizeof(NV_UI_Alarm_t),
                        (UINT8 *)&g_Alarm_Mng.Alarm);
    }

    if (SetRtcAlarm)
    {
        Alarm_Set_Recent_Alarm(TRUE, FALSE);
    }

    for (i = 0;i < NV_ALARM_MAX_ALARM_NUM;i++)
    {
        if (TRUE == g_Alarm_Mng.Alarm.AlarmInfo[i].OnOff)
        {
            Framework_Alarm_Set_Alarm_Ind(TRUE);
            break;
        }
    }
    if (NV_ALARM_MAX_ALARM_NUM == i)
    {
        Framework_Alarm_Set_Alarm_Ind(FALSE);
    }

    Framework_Restart_Backlight_Timer();
}

/**
 * Alarm ring timeout callback function
 * param (in) Para: VOID *
 * return  VOID
 */
VOID Alarm_Ring_Timeout_Cb(VOID *Para)
{
    g_Alarm_Mng.Timer = NULL;

    printf("%s: RingAlarmId %d, RtcAlarmId %d\n",
           __FUNCTION__, g_Alarm_Mng.RingAlarmId, g_Alarm_Mng.RtcAlarmId);
    if (NV_ALARM_MAX_ALARM_NUM <= g_Alarm_Mng.RingAlarmId)
    {
        printf("%s: wrong alarm id\n", __FUNCTION__);
        return;
    }

    Alarm_Ring_Stop_Handle(TRUE);
}

/**
 * Alarm ringing callback function
 * param (in) VOID
 * return  VOID
 */
VOID Alarm_Ringing_Cb(VOID)
{
    If_Setting_Play_Tone_t *PlayToneReq = NULL;
    UINT8                  i;
    BOOL                   AlarmChg = FALSE;
    ACTIVITY_ID            TopAct;

    TopAct = Nav_Get_Top();
    printf("%s: rtc alarm id %d, top act id %d\n", __FUNCTION__, g_Alarm_Mng.RtcAlarmId, TopAct);
    if ((ACT_ID_BOOT_ANIMATION == TopAct)
        || (ACT_ID_WELCOME_NOTE == TopAct))
    {
        printf("%s: ring during power on\n", __FUNCTION__);
        return;
    }
    else if ((ACT_ID_CALL_EMERGENCY_CALLING <= TopAct)
        && (ACT_ID_CALL_DTMF_INPUT >= TopAct))
    {
        // pending, buffer the alarm event, handle when the call is ended
        printf("%s: during call\n", __FUNCTION__);
        return;
    }
    else if ((ACT_ID_ALARM_RING_DELAY == TopAct)
        || (ACT_ID_ALARM_RING_OFF == TopAct))
    {
        if (g_Alarm_Mng.StatusTimer)
        {
            Hal_Timer_Stop(g_Alarm_Mng.StatusTimer);
            g_Alarm_Mng.StatusTimer = NULL;
        }
    }
    
    /* play tone start */
    PlayToneReq                = (If_Setting_Play_Tone_t *)Hal_Mem_Alloc(sizeof(If_Setting_Play_Tone_t));
    PlayToneReq->SimId         = MMI_MODEM_SIM_1;
    PlayToneReq->ToneType      = IF_SETTING_TONS_TYPE_ALARM;
    PlayToneReq->SpecToneIndex = g_Alarm_Mng.Alarm.ToneIndex;
    PlayToneReq->PlayCtrl      = IF_SETTING_PLAY_TONS_START;
    Setting_Play_Tone_Req(PlayToneReq);

    for (i = 0;i < NV_ALARM_MAX_ALARM_NUM;i++)
    {
        if (0 != (g_Alarm_Mng.RtcAlarmId & (0x01 << i)))
        {
            g_Alarm_Mng.RingAlarmId = i;
            break;
        }
    }

    // turn off the alarms with the same time
    for (i = g_Alarm_Mng.RingAlarmId + 1;i < NV_ALARM_MAX_ALARM_NUM;i++)
    {
        if (0 != (g_Alarm_Mng.RtcAlarmId & (0x01 << i)))
        {
            if (0 == (g_Alarm_Mng.Alarm.AlarmInfo[i].RepeatBitmap & 0x80))
            {
                Hal_Mem_Set(&g_Alarm_Mng.Alarm.AlarmInfo[i], 0, sizeof(NV_UI_Alarm_Info_t));
                AlarmChg = TRUE;
            }
            else if (0 < g_Alarm_Mng.Alarm.AlarmInfo[i].RepeatCount)
            {
                g_Alarm_Mng.Alarm.AlarmInfo[i].RepeatCount = 0;
                AlarmChg = TRUE;
            }
        }
    }
    if (TRUE == AlarmChg)
    {
        UI_NV_Write_Req(NV_SECTION_UI_ALARM,
                        0,
                        sizeof(NV_UI_Alarm_t),
                        (UINT8 *)&g_Alarm_Mng.Alarm);
    }

    Display_Alarm_Ring(g_Alarm_Mng.RingAlarmId);

    if (IF_FRAMEWORK_INIT_CHARGE == Framework_Get_Init_Type())
    {
        Framework_Display_Status_Bar(FALSE); // created after ACT_ID_ALARM_POWER_OFF_RING
    }

    g_Alarm_Mng.Timer = Hal_Timer_Start(ALARM_RING_TIMER_LEN,
                                        Alarm_Ring_Timeout_Cb,
                                        NULL,
                                        FALSE);

    Alarm_Set_Recent_Alarm(TRUE, TRUE);
}

/**
 * Set recent alarm to rtc, priority to set calendar alarm if the same time
 * param (in) AlarmChg: BOOL, TRUE if alarm time is changed for alarm module
 * param (in) ZeroSec: BOOL, current time(min:sec) is XX:00, not XX:59
 * return  VOID
 */
VOID Alarm_Set_Recent_Alarm(BOOL AlarmChg, BOOL ZeroSec)
{
    hal_rtc_t      CurrTime;
    hal_rtc_t      Alarm             = {0};
    UINT32         SecondCurr        = 0;
    UINT32         SecondTmp         = 0;
    UINT32         SecondAlarmRecent = 0xFFFFFFFF;
    UINT32         SecondAlarm       = 0;
    UINT8          RecentAlarmId     = 0;
    hal_rtc_t      AlarmRtc          = {0};
    UINT8          i;
    UINT8          j;
    If_Alarm_Calendar_Info_t CaleInfo = {0};
    INT8           Ret;

    Hal_Rtc_Gettime(&CurrTime);
    SecondCurr = UI_Time_to_Seconds(&CurrTime);
    if (ZeroSec && (50 < CurrTime.tm_sec))
    {
        SecondCurr += 60 - CurrTime.tm_sec;
    }
    printf("%s: %d/%d/%d,%d:%d:%d,wday %d,sec %d,AlarmChg %d\n",
           __FUNCTION__, CurrTime.tm_year, CurrTime.tm_mon, CurrTime.tm_mday, CurrTime.tm_hour,
           CurrTime.tm_min, CurrTime.tm_sec, CurrTime.tm_wday, SecondCurr, AlarmChg);

    if (TRUE == AlarmChg)
    {
        g_Alarm_Mng.RtcAlarmId = 0;
    }

    if (0 == g_Alarm_Mng.RtcAlarmId)
    {
        /* get alarm */
        for (i = 0; i < NV_ALARM_MAX_ALARM_NUM; i++)
        {
            if (TRUE == g_Alarm_Mng.Alarm.AlarmInfo[i].OnOff)
            {
                Hal_Mem_Set(&Alarm, 0, sizeof(hal_rtc_t));
                Alarm.tm_min = g_Alarm_Mng.Alarm.AlarmInfo[i].Min
                    + g_Alarm_Mng.Alarm.AlarmInfo[i].RepeatCount * ALARM_RING_REPEAT_INTERVAL;
                Alarm.tm_hour = (g_Alarm_Mng.Alarm.AlarmInfo[i].Hour + Alarm.tm_min / 60) % 24;
                Alarm.tm_min  = Alarm.tm_min % 60;
                Alarm.tm_mday = CurrTime.tm_mday;
                Alarm.tm_mon  = CurrTime.tm_mon;
                Alarm.tm_year = CurrTime.tm_year;
                SecondAlarm   = UI_Time_to_Seconds(&Alarm);

                if (0 == (g_Alarm_Mng.Alarm.AlarmInfo[i].RepeatBitmap & 0x80)) // alarm once
                {
                    if ((SecondCurr >= SecondAlarm) && (0 == g_Alarm_Mng.Alarm.AlarmInfo[i].RepeatCount))
                    {
                        SecondAlarm += ALARM_SECONDS_FOR_ONE_DAY; // add one day
                    }
                    if (SecondAlarmRecent > SecondAlarm)
                    {
                        SecondAlarmRecent = SecondAlarm;
                        RecentAlarmId     = 0x01 << i;
                    }
                    else if (SecondAlarmRecent == SecondAlarm)
                    {
                        RecentAlarmId |= 0x01 << i;
                    }
                }
                else    // alarm repeat
                {
                    for (j = 0; j < 7; j++) // 7 days in a week
                    {
                        if (0x01 == ((g_Alarm_Mng.Alarm.AlarmInfo[i].RepeatBitmap >> j) & 0x01))
                        {
                            SecondTmp = SecondAlarm + ((j - CurrTime.tm_wday + 7) % 7) * ALARM_SECONDS_FOR_ONE_DAY;
                            if (SecondCurr >= SecondTmp)
                            {
                                SecondTmp += ALARM_SECONDS_FOR_ONE_WEEK; // add one week
                            }
                            if (SecondAlarmRecent > SecondTmp)
                            {
                                SecondAlarmRecent = SecondTmp;
                                RecentAlarmId     = 0x01 << i;
                            }
                            else if (SecondAlarmRecent == SecondTmp)
                            {
                                RecentAlarmId |= 0x01 << i;
                            }
                        }
                    }
                }
            }
        }
    }
    else
    {
        Hal_Rtc_Get_Alarm(RTC_ALARM_1, &Alarm);
        SecondAlarmRecent = UI_Time_to_Seconds(&Alarm);
        RecentAlarmId     = g_Alarm_Mng.RtcAlarmId;
    }

    /* get calendar alarm */
    Ret = Alarm_Calendar_Get_Alarm_Info_Req(SecondCurr, SecondAlarmRecent, &CaleInfo);
    if (0 >= Ret) // set calendar alarm to rtc
    {
        if (CaleInfo.CallBack)
        {
            Hal_Mem_Set(&Alarm, 0, sizeof(hal_rtc_t));
            AlarmRtc.tm_min  = CaleInfo.AlarmTime.Min;
            AlarmRtc.tm_hour = CaleInfo.AlarmTime.Hour;
            AlarmRtc.tm_mday = CaleInfo.AlarmTime.Day;
            AlarmRtc.tm_mon  = CaleInfo.AlarmTime.Month;
            AlarmRtc.tm_year = CaleInfo.AlarmTime.Year;
            printf("%s: enable calendar alarm, %d/%d/%d, %d:%d\n",
                   __FUNCTION__, AlarmRtc.tm_year, AlarmRtc.tm_mon,
                   AlarmRtc.tm_mday, AlarmRtc.tm_hour, AlarmRtc.tm_min);

            Hal_Rtc_Enable_Alarm(RTC_ALARM_1, TRUE);
            Hal_Rtc_Set_Alarm(RTC_ALARM_1, &AlarmRtc, CaleInfo.CallBack);
        }
        if (0 == Ret)
        {
            g_Alarm_Mng.RtcAlarmId = RecentAlarmId;
        }
        else
        {
            g_Alarm_Mng.RtcAlarmId = 0;
        }
    }
    else if (0 != RecentAlarmId)
    {
        if (0 == g_Alarm_Mng.RtcAlarmId)
        {
            g_Alarm_Mng.RtcAlarmId = RecentAlarmId;
            UI_Seconds_to_Time(SecondAlarmRecent, &AlarmRtc);
            printf("%s: enable alarm id %d, %d/%d/%d, %d:%d\n",
                   __FUNCTION__, RecentAlarmId, AlarmRtc.tm_year, AlarmRtc.tm_mon,
                   AlarmRtc.tm_mday, AlarmRtc.tm_hour, AlarmRtc.tm_min);

            Hal_Rtc_Enable_Alarm(RTC_ALARM_1, TRUE);
            Hal_Rtc_Set_Alarm(RTC_ALARM_1, &AlarmRtc, Alarm_Ringing_Cb);
        }
    }
    else
    {
        g_Alarm_Mng.RtcAlarmId = 0;
        Hal_Rtc_Enable_Alarm(RTC_ALARM_1, FALSE);
    }
} /* Alarm_Set_Recent_Alarm */
